/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package operators;
import genotypes.Angles;
import genotypes.AnglesPopulation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
/**
 *
 * @author rusak
 */
public class BetaMutCrossover2 implements CrossoverOperator{
    Random r = new Random();

    private int[] randomPermutation(int size) {
        ArrayList<Integer> set = new ArrayList<Integer>();
        int result[] = new int[size];
        for (int i = 0; i < size; i++) {
            set.add(new Integer(i));
        }
        Random r = new Random();
        int who;
        for (int i = size; i > 0; i--) {
            who = r.nextInt(i);
            result[i - 1] = set.get(who);
            set.remove(who);
        }
        return result;
    }

    private boolean theSame(double an1[], double an2[]) {
        int len = an1.length;
        for (int i = 0; i < len; i++) {
            if(an1[i] != an2[i]) return false;
        }
        return true;
    }

    @Override
    public AnglesPopulation crossover(AnglesPopulation population, double[][] limitations) {
        int size = population.getSize();

        double beta;
        double an1[], an2[], newan1[], newan2[];
        Angles results[] = new Angles[size];
        int anglesLength = population.getAnglesAt(0).getAngles().length;
        int perm[] = randomPermutation(size);
        for (int i = 0; i < size - 1; i += 2) {
            an1 = population.getAnglesAt(perm[i]).getAngles();
            an2 = population.getAnglesAt(perm[i + 1]).getAngles();
            newan1 = new double[anglesLength];
            newan2 = new double[anglesLength];
            if (theSame(an1, an2)) {
                results[i] = mutate(mutate(an1,limitations).getAngles(),limitations);
                results[i+1] = mutate(mutate(an2, limitations).getAngles(),limitations);
                /*System.out.println("Crossover: ");
                System.out.println(population.getAnglesAt(perm[i]));
                System.out.println(population.getAnglesAt(perm[i+1]));
                System.out.println("WYszlo: ");
                System.out.println(results[i]);
                System.out.println(results[i+1]);*/
            } else {
                beta = r.nextDouble();

                //beta = 0.5;

                for (int j = 0; j < anglesLength; j++) {

                    newan1[j] = (an1[j] + an2[j] - beta * (an1[j] - an2[j])) / 2;
                    newan2[j] = (an1[j] + an2[j] + beta * (an1[j] - an2[j])) / 2;
                    if (newan1[j] < limitations[j][0]) {
                        newan1[j] = limitations[j][0];
                    } else if (newan1[j] > limitations[j][1]) {
                        newan1[j] = limitations[j][1];
                    }
                    if (newan2[j] < limitations[j][0]) {
                        newan2[j] = limitations[j][0];
                    } else if (newan2[j] > limitations[j][1]) {
                        newan2[j] = limitations[j][1];
                    }
                }
                results[i] = new Angles(newan1);
                results[i + 1] = new Angles(newan2);
                /*System.out.println("Crossover: ");
                System.out.println(population.getAnglesAt(perm[i]));
                System.out.println(population.getAnglesAt(perm[i+1]));
                System.out.println("WYszlo: ");
                System.out.println(results[i]);
                System.out.println(results[i+1]);*/
            }
        }
        return new AnglesPopulation(results);
    }
    
     public Angles mutate(double angles[], double[][] limitations) {
        int indSize = angles.length;
        double an[] = Arrays.copyOf(angles, indSize);
        //szansa mutacji na razie na sztywno

        int where = r.nextInt(indSize);
        double scale = limitations[where][1] - limitations[where][0];

        an[where] = r.nextDouble() * scale + limitations[where][0];

        if (an[where] < limitations[where][0]) {
            an[where] = limitations[where][0];
        } else if (an[where] > limitations[where][1]) {
            an[where] = limitations[where][1];
        }

        return new Angles(an);
    }
}
